package org.tigris.atlas.webservice.service.delegate;

import java.util.Properties;

import org.apache.commons.logging.Log;
import org.tigris.atlas.config.ConfigurationManager;

/**
 * This class contains the common functionality needed to perform the location
 * of the base URL from which relative paths will used to locate a web service.
 */
public abstract class WebServiceDelegate {
	
	private static final String LOCATION_LOCALHOST_7001 = "localhost:7001";
	private static final String PROTOCOL_HTTP = "http";
	private static final String SERVICE_DELEGATE_PROPERTIES = "/service-delegate.properties";
	private static final String BASE_LOCATION = "base.location";
	private static final String LOCATION = "location";
	private static final String PROTOCOL = "protocol";
	private static final String DEFAULT = "default.";
	private static final String DEFAULT_LOCATION = DEFAULT + LOCATION;
	private static final String DEFAULT_PROTOCOL = DEFAULT + PROTOCOL;
	
	protected String getBaseUrlForService() {	
		Log log = getLog();
		
		Properties serviceDelegateProperties = null;
		try {
			serviceDelegateProperties = ConfigurationManager.getConfiguration(SERVICE_DELEGATE_PROPERTIES);						
		} catch (IllegalStateException ex) {
			if (log.isWarnEnabled()) {
				log.warn("Unable to use the ConfigurationManager", ex);
			}
			serviceDelegateProperties = new Properties();
		}
		String protocol = getServiceProtocol(log, serviceDelegateProperties);
		String location = getServiceLocation(log, serviceDelegateProperties);		
		
		StringBuffer sb = new StringBuffer(200);
		sb.append(protocol);
		sb.append("://");
		sb.append(location);
		
		String baseUrl = sb.toString();
		
		return baseUrl;
	}
	
	/**
	 * @param defaultProtocol
	 * @param log
	 * @param defaultLocation
	 * @return
	 */
	private String getServiceLocation(Log log, Properties serviceDelegateProperties) {
		String defaultLocation = getDefaultLocation(log, serviceDelegateProperties);
		String serviceName = getServiceName();
		String servicePropertyName = serviceName + "." + LOCATION;
		String serviceLocation = serviceDelegateProperties.getProperty(servicePropertyName);
		serviceLocation = checkForValue(servicePropertyName, serviceLocation, defaultLocation, log);
		return serviceLocation;
	}
	
	/**
	 * @param defaultProtocol
	 * @param log
	 * @param defaultProtocol
	 * @return
	 */
	private String getServiceProtocol(Log log, Properties serviceDelegateProperties) {
		String defaultProtocol = getDefaultProtocol(log, serviceDelegateProperties);
		String serviceName = getServiceName();
		String servicePropertyName = serviceName + "." + PROTOCOL;
		String serviceProtocol = serviceDelegateProperties.getProperty(servicePropertyName);
		serviceProtocol = checkForValue(servicePropertyName, serviceProtocol, defaultProtocol, log);
		return serviceProtocol;
	}

	/**
	 * @param defaultProtocol
	 * @param log
	 * @return
	 */
	private String getDefaultProtocol(Log log, Properties serviceDelegateProperties) {
		String defaultProtocol = serviceDelegateProperties.getProperty(DEFAULT_PROTOCOL);
		String protocol = checkForValue(DEFAULT_PROTOCOL, defaultProtocol, PROTOCOL_HTTP, log);
		return protocol;
	}

	/**
	 * Determine the default location of a web service
	 * @param log
	 * @param serviceDelegateProperties
	 * @return The default location of a web service
	 */
	private String getDefaultLocation(Log log, Properties serviceDelegateProperties) {
		String baseLocation;
		String defaultLocation;
		baseLocation = serviceDelegateProperties.getProperty(BASE_LOCATION);
		defaultLocation = serviceDelegateProperties.getProperty(DEFAULT_LOCATION);
		//for the time being, continue to support base.location, but only use it is default.location is not specified:
		if (defaultLocation != null) {
			defaultLocation = checkForValue(DEFAULT_LOCATION, defaultLocation, LOCATION_LOCALHOST_7001, log);
			
		} else {
			defaultLocation = checkForValue(BASE_LOCATION, baseLocation, LOCATION_LOCALHOST_7001, log);
			if (baseLocation != null) {
				log.warn("The service-delegate.properties property '" + 
					BASE_LOCATION + "' has been deprecated.  Please switch to '" + DEFAULT_LOCATION + "' instead.");
			}
			
		}
		
		return defaultLocation;
	}

	/**
	 * Checks for a value and sets that value to a default, if specified
	 * @param propertyName
	 * @param propertyValue
	 * @param defaultValue
	 * @param log
	 * @return The value in question
	 */
	private String checkForValue(String propertyName, String propertyValue, String defaultValue, Log log) {
		if (propertyValue != null) {
			if (log.isInfoEnabled()) {
				log.info(propertyName + ": " + propertyValue);
			}
			
		} else {
			propertyValue = defaultValue;
			if (log.isInfoEnabled()) {
				log.info("No " + propertyName + " property was defined in service-delegate.properties!  Defaulting to: " + propertyValue);
			}
			
		}
		return propertyValue;
	}
	
	/**
	 * Returns the log for this class to allow for more descriptive debugging in superclasses
	 * @return The <tt>Log</tt> instance for the this class
	 */
	protected abstract Log getLog();
	
	/**
	 * Returns the service name for which a property can be looked up.
	 * @return The name of the service used in service-delegate.properties
	 */
	protected abstract String getServiceName();

}
